//---------------------------------------------------------------------------
// <copyright file="RibbonContextualTabGroupItemsControl.cs" company="Microsoft Corporation">
//     Copyright (C) Microsoft Corporation.  All rights reserved.
// </copyright>
//---------------------------------------------------------------------------

namespace Microsoft.Windows.Controls.Ribbon.Primitives
{
	using MS.Internal;
	using System;
	using System.Windows;
	using System.Windows.Controls;
	using System.Windows.Controls.Primitives;

	public class RibbonContextualTabGroupsPanel : Panel
	{
		static RibbonContextualTabGroupsPanel()
		{
		}

		#region Protected Methods

		protected override Size MeasureOverride(Size availableSize)
		{
			Size desiredSize = new Size();

			// Don't measure the child if tabs are not ready yet or Ribbon is collapsed.
			if (Ribbon != null && !Ribbon.IsCollapsed)
			{
				double remainingSpace = availableSize.Width;
				bool invalidateTHPanel = false;
				RibbonTabHeadersPanel tabHeadersPanel = null;
				if (Ribbon.RibbonTabHeaderItemsControl != null)
				{
					tabHeadersPanel = Ribbon.RibbonTabHeaderItemsControl.InternalItemsHost as RibbonTabHeadersPanel;
				}
				double tabHeadersPanelSpaceAvailable = (tabHeadersPanel != null) ? tabHeadersPanel.SpaceAvailable : 0.0;

				foreach (RibbonContextualTabGroup tabGroupHeader in InternalChildren)
				{
					double width = 0;
					tabGroupHeader.ArrangeWidth = 0;
					tabGroupHeader.ArrangeX = 0;
					tabGroupHeader.IdealDesiredWidth = 0.0;

					if (tabGroupHeader.Visibility == Visibility.Visible && tabGroupHeader.FirstVisibleTab != null && DoubleUtil.GreaterThanOrClose(remainingSpace, 0.0))
					{
						// Measure the maximum desired width 
						// TabHeaders should be padded up more if needed. 
						// Also we need to determine if we need to show the label tooltip
						tabGroupHeader.Measure(new Size(double.PositiveInfinity, availableSize.Height));
						tabGroupHeader.IdealDesiredWidth = tabGroupHeader.DesiredSize.Width;

						// If TabHeadersPanel has space to expand, then invalidate it so that TabHeaders add extra Padding to themselves. 
						double desiredExtraPadding = tabGroupHeader.IdealDesiredWidth - tabGroupHeader.TabsDesiredWidth;
						if (DoubleUtil.GreaterThan(desiredExtraPadding, 0.0) &&
							DoubleUtil.GreaterThan(tabHeadersPanelSpaceAvailable, 0.0))
						{
							invalidateTHPanel = true;
						}

						width = tabGroupHeader.TabsDesiredWidth;
						// If the difference between tabGroupHeader.TabsDesiredWidth and remainingSpace is less
						// than 1e-10 then assume that both are same. This is because TextBlock is very sensitive to 
						// even a minute floating point difference and displays ellipsis even when sufficient
						// space is available. 
						if (Math.Abs(tabGroupHeader.TabsDesiredWidth - remainingSpace) > _desiredWidthEpsilon)
						{
							// Clip on the  left side
							width = Math.Min(tabGroupHeader.TabsDesiredWidth, remainingSpace);
						}

						tabGroupHeader.ArrangeWidth = width;
						tabGroupHeader.Measure(new Size(width, availableSize.Height));

						// If label is truncated - show the tooltip
						tabGroupHeader.ShowLabelToolTip = DoubleUtil.GreaterThan(tabGroupHeader.IdealDesiredWidth, width);

						remainingSpace = remainingSpace - width;
					}

					desiredSize.Width += width;
					desiredSize.Height = Math.Max(desiredSize.Height, tabGroupHeader.DesiredSize.Height);
				}

				if (WaitingForMeasure || invalidateTHPanel)
				{
					if (tabHeadersPanel != null)
					{
						tabHeadersPanel.InvalidateMeasure();
					}
				}
			}

			return desiredSize;
		}

		protected override Size ArrangeOverride(Size finalSize)
		{
			double startX = 0.0;
			foreach (RibbonContextualTabGroup tabGroupHeader in InternalChildren)
			{
				double width = Math.Max(tabGroupHeader.ArrangeWidth, 0);
				double height = tabGroupHeader.DesiredSize.Height;
				double y = finalSize.Height - height;

				tabGroupHeader.ArrangeX = startX;
				tabGroupHeader.Arrange(new Rect(startX, y, width, Math.Max(0.0, height - 1)));

				startX += width;
			}

			//InvalidateVisual(); // Ensure OnRender is called to draw the separators

			return finalSize;
		}

		///// <summary>
		/////   Draws separators for the RibbonContextualTabGroups.
		///// </summary>
		///// <param name="drawingContext">The drawing context to use.</param>
		//protected override void OnRender(DrawingContext drawingContext)
		//{
		//	if (!SystemParameters.HighContrast)
		//	{
		//		// Calculate separatorHeight
		//		double separatorHeight = 0.0;
		//		if (Ribbon != null && Ribbon.RibbonTabHeaderItemsControl != null && Ribbon.RibbonTabHeaderItemsControl.InternalItemsHost != null)
		//		{
		//			separatorHeight = Ribbon.RibbonTabHeaderItemsControl.InternalItemsHost.ActualHeight - RibbonContextualTabGroup.TabHeaderSeparatorHeightDelta;
		//		}

		//		Pen separatorPen = SeparatorPen;
		//		if (separatorPen != null)
		//		{
		//			foreach (RibbonContextualTabGroup tabGroupHeader in InternalChildren)
		//			{
		//				if (tabGroupHeader.Visibility == Visibility.Visible && tabGroupHeader.ArrangeWidth > 0)
		//				{
		//					double startX = tabGroupHeader.ArrangeX;
		//					if (DoubleUtil.AreClose(startX, 0.0))
		//					{
		//						// For the first group, draw to the left as well
		//						drawingContext.DrawLine(separatorPen, new Point(startX, ActualHeight), new Point(startX, this.ActualHeight + separatorHeight));
		//					}
		//					// draw separator to the right at _group.DesiredWidth
		//					drawingContext.DrawLine(separatorPen, new Point(startX + tabGroupHeader.TabsDesiredWidth, ActualHeight), new Point(startX + tabGroupHeader.TabsDesiredWidth, this.ActualHeight + separatorHeight));
		//				}
		//			}
		//		}
		//	}

		//	base.OnRender(drawingContext);
		//}


		/// <summary>
		///     This method is invoked when the IsItemsHost property changes.
		/// </summary>
		/// <param name="oldIsItemsHost">The old value of the IsItemsHost property.</param>
		/// <param name="newIsItemsHost">The new value of the IsItemsHost property.</param>
		protected override void OnIsItemsHostChanged(bool oldIsItemsHost, bool newIsItemsHost)
		{
			base.OnIsItemsHostChanged(oldIsItemsHost, newIsItemsHost);

			if (newIsItemsHost)
			{
				RibbonContextualTabGroupItemsControl groupHeaderItemsControl = ParentItemsControl;
				if (groupHeaderItemsControl != null)
				{
					IItemContainerGenerator generator = groupHeaderItemsControl.ItemContainerGenerator as IItemContainerGenerator;
					if (generator != null && generator.GetItemContainerGeneratorForPanel(this) == generator)
					{
						groupHeaderItemsControl.InternalItemsHost = this;
					}
				}
			}
			else
			{
				RibbonContextualTabGroupItemsControl groupHeaderItemsControl = ParentItemsControl;
				if (groupHeaderItemsControl != null && groupHeaderItemsControl.InternalItemsHost == this)
				{
					groupHeaderItemsControl.InternalItemsHost = null;
				}
			}
		}

		#endregion

		#region Private Members

		/// <summary>
		///     DependencyProperty for Ribbon property.
		/// </summary>
		public static readonly DependencyProperty RibbonProperty =
			RibbonControlService.RibbonProperty.AddOwner(typeof(RibbonContextualTabGroupsPanel));

		/// <summary>
		///     This property is used to access visual style brushes defined on the Ribbon class.
		/// </summary>
		public Ribbon Ribbon
		{
			get { return RibbonControlService.GetRibbon(this); }
		}

		/// <summary>
		///     The parent ItemsControl
		/// </summary>
		private RibbonContextualTabGroupItemsControl ParentItemsControl
		{
			get
			{
				return TreeHelper.FindTemplatedAncestor<RibbonContextualTabGroupItemsControl>(this);
			}
		}

		/// <summary>
		/// RibbonTabHeadersPanels (THPanel) and RibbonContextualTabGroupsPanel (CTGHPanel) Measure are interdependent.
		/// CTGHPanel's Measure requires THPanel to be measured. Hence THPanel always call InvalidateMeasure on CTGHPanel after its Measure.
		/// THPanel's Measure requires that CTGHPanel's containers are generated. 
		/// If they are not, then THPanel sets this flag to indicate that it is waiting on CTGHPanel.Measure.  
		/// CTGHPanel checks this flag and then InvalidatesMeasure on THPanel. THPanel unsets this flag after a successful Measure.
		/// We need this flag to avoid an infinite loop between THPanel.Measure and CTGHPanel.Measure.
		/// </summary>
		internal bool WaitingForMeasure
		{
			get;
			set;
		}

		//private Pen SeparatorPen
		//{
		//	get
		//	{
		//		if (_separatorPen == null)
		//		{
		//			Ribbon ribbon = Ribbon;
		//			if (ribbon != null && ribbon.BorderBrush != null)
		//			{
		//				Brush b = ribbon.BorderBrush.Clone();
		//				_separatorPen = new Pen(b, 1.0);
		//			}
		//		}
		//		return _separatorPen;
		//	}
		//}

		internal void OnNotifyRibbonBorderBrushChanged()
		{
			//_separatorPen = null;
			InvalidateVisual();
		}

		//Pen _separatorPen;
		private const double _desiredWidthEpsilon = 1e-10;

		#endregion
	}
}
